<!DOCTYPE html>
<html lang="en"><head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script>
    MathJax = {
      tex: {
        inlineMath: [['$', '$'], ['\\(', '\\)']]
      },
      svg: {
        fontCache: 'global'
      }
    };
  </script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<title>Creating an Unkillable Process by Abusing Character Devices | friday@ortiz.sh:~$</title>
<meta name="generator" content="Jekyll v3.9.2" />
<meta property="og:title" content="Creating an Unkillable Process by Abusing Character Devices" />
<meta name="author" content="Friday Ortiz" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="TL;DR: This is probably a bad idea and you don’t actually want use this. Whatever problem you’re trying to solve, there’s probably a better way. I was researching ways to prevent a process from dying prematurely and created a simple “device driver” that will prevent a given process from being killed until the system is powered down or the process decides to end on its own terms." />
<meta property="og:description" content="TL;DR: This is probably a bad idea and you don’t actually want use this. Whatever problem you’re trying to solve, there’s probably a better way. I was researching ways to prevent a process from dying prematurely and created a simple “device driver” that will prevent a given process from being killed until the system is powered down or the process decides to end on its own terms." />
<link rel="canonical" href="https://ortiz.sh/linux/2020/07/05/UNKILLABLE.html" />
<meta property="og:url" content="https://ortiz.sh/linux/2020/07/05/UNKILLABLE.html" />
<meta property="og:site_name" content="friday@ortiz.sh:~$" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2020-07-05T02:00:00+00:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="Creating an Unkillable Process by Abusing Character Devices" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"Friday Ortiz"},"dateModified":"2020-07-05T02:00:00+00:00","datePublished":"2020-07-05T02:00:00+00:00","description":"TL;DR: This is probably a bad idea and you don’t actually want use this. Whatever problem you’re trying to solve, there’s probably a better way. I was researching ways to prevent a process from dying prematurely and created a simple “device driver” that will prevent a given process from being killed until the system is powered down or the process decides to end on its own terms.","headline":"Creating an Unkillable Process by Abusing Character Devices","mainEntityOfPage":{"@type":"WebPage","@id":"https://ortiz.sh/linux/2020/07/05/UNKILLABLE.html"},"url":"https://ortiz.sh/linux/2020/07/05/UNKILLABLE.html"}</script>

<link rel="stylesheet" href="/assets/main.css"><link type="application/atom+xml" rel="alternate" href="https://ortiz.sh/feed.xml" title="friday@ortiz.sh:~$" /><script>
if(!(window.doNotTrack === "1" || navigator.doNotTrack === "1" || navigator.doNotTrack === "yes" || navigator.msDoNotTrack === "1")) {
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-172023923-1', 'auto');
  ga('send', 'pageview');
}
</script>
</head>
<body><header class="site-header">
<div class="wrapper"><a class="site-title" rel="author" href="/"><span class="__cf_email__" data-cfemail="2b4d59424f4a526b44595f4251055843">[email&#160;protected]</span>:~$</a><nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger">
<span class="menu-icon">
<svg viewBox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z" />
</svg>
</span>
</label>
<div class="trigger"><a class="page-link" href="/cv/">CV &amp; Resume</a><a class="page-link" href="/contact/">Contact Me</a><a class="page-link" href="/services/">Public Services</a><a class="page-link" href="/tag.html">Tags</a></div>
</nav></div>
</header><main class="page-content" aria-label="Content">
<div class="wrapper">
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
<header class="post-header">
<h1 class="post-title p-name" itemprop="name headline">Creating an Unkillable Process by Abusing Character Devices</h1>
<p class="post-meta"><time class="dt-published" datetime="2020-07-05T02:00:00+00:00" itemprop="datePublished">
Jul 5, 2020
</time>
<br />
<span>
Tags:
<a class="tag" href="/tag.html#linux">linux</a>,
<a class="tag" href="/tag.html#security">security</a>
</span>
</p>
</header>
<div class="post-content e-content" itemprop="articleBody">
<p>TL;DR: This is probably a bad idea and you don’t actually want use this.
Whatever problem you’re trying to solve, <a href="https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem/243965#243965">there’s probably a better way.</a>
I was researching ways to prevent a process from dying prematurely and
created a simple “device driver” that will prevent a given process from
being killed until the system is powered down or the process decides to end
on its own terms.</p>
<h1 id="why-create-an-unkillable-process">Why create an unkillable process?</h1>
<p>I was looking for ways to protect a process from being accidentally or
maliciously halted for a research project at work. Signal handlers did the
trick, but unfortunately <a href="https://man7.org/linux/man-pages/man2/signal.2.html">signal handlers can’t handle <code class="language-plaintext highlighter-rouge">SIGKILL</code>:</a></p>
<blockquote>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  The signals SIGKILL and SIGSTOP cannot be caught or ignored.
</code></pre></div> </div>
</blockquote>
<p>The section 7 entry for <code class="language-plaintext highlighter-rouge">signal</code> <a href="https://man7.org/linux/man-pages/man7/signal.7.html">basically says the same:</a></p>
<blockquote>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  The signals SIGKILL and SIGSTOP cannot be caught, blocked, or
  ignored.
</code></pre></div> </div>
</blockquote>
<p>In fact, this piece of advice <a href="https://stackoverflow.com/questions/2541597/how-to-gracefully-handle-the-sigkill-signal-in-java/2541618#2541618">kept</a>
<a href="https://stackoverflow.com/a/15766845">popping</a> <a href="https://stackoverflow.com/a/3908710">up</a>
<a href="https://www.reddit.com/r/golang/comments/6a76pl/syscallkillpid_syscallsigkill_not_immediate/dhdhxv1">everywhere</a>.
The Internet seems to have taken the man page at face value as ultimate truth.
<code class="language-plaintext highlighter-rouge">SIGKILL</code> cannot be caught and it cannot be ignored. The signal is never sent
to the process, the kernel manages <code class="language-plaintext highlighter-rouge">SIGKILL</code> on its own, cleans up the process,
and the process is never heard from again. It simply vanishes!</p>
<p>Except that’s not quite true. Process 1, <code class="language-plaintext highlighter-rouge">init</code>, will <a href="https://unix.stackexchange.com/a/484452">ignore any terminating signals sent to it</a>.
That includes <code class="language-plaintext highlighter-rouge">SIGKILL</code>. <code class="language-plaintext highlighter-rouge">init</code> is a <a href="https://stackoverflow.com/questions/23277706/does-linux-init-process-run-in-kernel-or-user-mode">userland process</a>,
so clearly this is possible. And that means <em>the Internet is wrong!</em>
I couldn’t find a better source for <code class="language-plaintext highlighter-rouge">init</code> being immune to <code class="language-plaintext highlighter-rouge">SIGKILL</code> than
stackexchange, unfortunately. It doesn’t appear to be well documented.
But if you’re following along at home, go ahead and try it! It’s perfectly
harmless. Send some <code class="language-plaintext highlighter-rouge">SIGKILL</code>s at your <code class="language-plaintext highlighter-rouge">init</code> process, pid 1.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo kill -9 1
$ ps aux | grep init
root           1  0.1  0.0 168580 12384 ?        Ss   17:11   0:12 /sbin/init splash
$ sudo kill -9 1
$ ps aux | grep init
root           1  0.1  0.0 168580 12384 ?        Ss   17:11   0:12 /sbin/init splash
$ Why won't you die?
&gt; bash: unexpected EOF while looking for matching `''
</code></pre></div></div>
<p>Maybe it was out of morbid curiosity, or a desire to prove the Internet wrong,
but I wanted to create another user process which could not be killed.</p>
<h1 id="creating-an-unkillable-process">Creating an unkillable process.</h1>
<p>So how do we prove the Internet wrong (for this very specific case)? Let’s look
at what actually makes <code class="language-plaintext highlighter-rouge">init</code> unkillable. I’ll spare you how I got here
and skip right the point. First, we have to define <code class="language-plaintext highlighter-rouge">task_struct</code>.
I recommend reading through the <a href="https://elixir.bootlin.com/linux/latest/source/include/linux/sched.h#L632">kernel source</a>,
it’s not too complex. The gist is that <a href="https://stackoverflow.com/a/56538295"><code class="language-plaintext highlighter-rouge">task_struct</code> holds information about a process</a>
for use by the kernel.</p>
<p><a href="https://elixir.bootlin.com/linux/latest/source/include/linux/sched.h#L925">Further down</a>
in <code class="language-plaintext highlighter-rouge">task_struct</code> we find a reference to a <code class="language-plaintext highlighter-rouge">signal_struct</code> called <code class="language-plaintext highlighter-rouge">*signal</code>:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Signal handlers: */</span>
<span class="k">struct</span> <span class="n">signal_struct</span>		<span class="o">*</span><span class="n">signal</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">sighand_struct</span> <span class="n">__rcu</span>	<span class="o">*</span><span class="n">sighand</span><span class="p">;</span>
</code></pre></div></div>
<p>The comment hints that the purpose of this structure is handling signals. If we
dig into <a href="https://elixir.bootlin.com/linux/latest/source/include/linux/sched/signal.h#L82"><code class="language-plaintext highlighter-rouge">signal_struct</code>’s definition</a>
we see <a href="https://elixir.bootlin.com/linux/latest/source/include/linux/sched/signal.h#L111">this interesting line</a>:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">unsigned</span> <span class="kt">int</span>		<span class="n">flags</span><span class="p">;</span> <span class="cm">/* see SIGNAL_* flags below */</span>
</code></pre></div></div>
<p>Scroll down to <a href="https://elixir.bootlin.com/linux/latest/source/include/linux/sched/signal.h#L240">where signal flags are defined</a>
and we find <a href="https://elixir.bootlin.com/linux/latest/source/include/linux/sched/signal.h#L253">what we’re looking for</a>:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define SIGNAL_UNKILLABLE	0x00000040 </span><span class="cm">/* for init: ignore fatal signals */</span><span class="cp">
</span></code></pre></div></div>
<p>A flag, for <code class="language-plaintext highlighter-rouge">init</code>, that marks the signal handler for this <code class="language-plaintext highlighter-rouge">init</code>’s <code class="language-plaintext highlighter-rouge">task_struct</code>
as “unkillable” and tells it to ignore fatal signals. Now we’re getting
somewhere! If we want to make an arbitrary process unkillable we simply
need to add the <code class="language-plaintext highlighter-rouge">SIGNAL_UNKILLABLE</code> flag to the process’s <code class="language-plaintext highlighter-rouge">task_struct</code>’s
<code class="language-plaintext highlighter-rouge">signal_struct</code>.</p>
<p>The correct way to do this would be to add a new syscall that marks an
arbitrary process as unkillable with the flag. Unfortunately, adding a syscall
required <a href="https://medium.com/anubhav-shrimal/adding-a-hello-world-system-call-to-linux-kernel-dad32875872">recompiling the kernel</a>
and I want to avoid doing that. This is already a bit of a hack, so why make
things harder. Luckily, we can get our kernel to run arbitrary code by
loading a new module. That only requires root privileges, no recompiling.</p>
<p>We will need a program we want to make immortal and a Linux Kernel Module that
marks it as such. Let’s start with the LKM.</p>
<p>First we’ll take a boilerplate character device driver and use take advantage
of the <code class="language-plaintext highlighter-rouge">read()</code> function to communicate an arbitrary pid. Then we’ll find
that pid’s <code class="language-plaintext highlighter-rouge">task_struct</code> and assign the <code class="language-plaintext highlighter-rouge">signal_struct</code> the <code class="language-plaintext highlighter-rouge">SIGNAL_UNKILLABLE</code>
flag.</p>
<h4 id="unkillablec"><em>unkillable.c</em></h4>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;linux/init.h&gt;
#include &lt;linux/module.h&gt;
#include &lt;linux/kernel.h&gt;
#include &lt;linux/types.h&gt;
#include &lt;linux/proc_fs.h&gt;
#include &lt;linux/sched.h&gt;
#include &lt;linux/sched/signal.h&gt;
#include &lt;linux/pid.h&gt;
</span>
<span class="n">MODULE_LICENSE</span><span class="p">(</span><span class="s">"GPL"</span><span class="p">);</span>

<span class="kt">void</span> <span class="nf">unkillable_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="kt">int</span> <span class="nf">unkillable_init</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>

<span class="cm">/* device access functions */</span>
<span class="kt">ssize_t</span> <span class="nf">unkillable_write</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">count</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="n">f_pos</span><span class="p">);</span>
<span class="kt">ssize_t</span> <span class="nf">unkillable_read</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">count</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="n">f_pos</span><span class="p">);</span>
<span class="kt">int</span> <span class="nf">unkillable_open</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">);</span>
<span class="kt">int</span> <span class="nf">unkillable_release</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">);</span>
<span class="k">struct</span> <span class="n">file_operations</span> <span class="n">unkillable_fops</span> <span class="o">=</span> <span class="p">{</span>
	<span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">unkillable_read</span><span class="p">,</span>
	<span class="p">.</span><span class="n">write</span> <span class="o">=</span> <span class="n">unkillable_write</span><span class="p">,</span>
	<span class="p">.</span><span class="n">open</span> <span class="o">=</span> <span class="n">unkillable_open</span><span class="p">,</span>
	<span class="p">.</span><span class="n">release</span> <span class="o">=</span> <span class="n">unkillable_release</span>
<span class="p">};</span>

<span class="cm">/* Declaration of the init and exit functions */</span>
<span class="n">module_init</span><span class="p">(</span><span class="n">unkillable_init</span><span class="p">);</span>
<span class="n">module_exit</span><span class="p">(</span><span class="n">unkillable_exit</span><span class="p">);</span>

<span class="kt">int</span> <span class="n">unkillable_major</span> <span class="o">=</span> <span class="mi">117</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">unkillable_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> 
<span class="p">{</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">register_chrdev</span><span class="p">(</span><span class="n">unkillable_major</span><span class="p">,</span> <span class="s">"unkillable"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">unkillable_fops</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="p">)</span> <span class="p">{</span>
		<span class="n">printk</span><span class="p">(</span><span class="s">"Unkillable: cannot obtain major number %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">unkillable_major</span><span class="p">);</span>
		<span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="n">printk</span><span class="p">(</span><span class="s">"Inserting unkillable module</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> 
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">unkillable_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> 
<span class="p">{</span>
	<span class="n">unregister_chrdev</span><span class="p">(</span><span class="n">unkillable_major</span><span class="p">,</span> <span class="s">"unkillable"</span><span class="p">);</span>
	<span class="n">printk</span><span class="p">(</span><span class="s">"Removing unkillable module</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">unkillable_open</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">)</span> 
<span class="p">{</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">unkillable_release</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">)</span> 
<span class="p">{</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">ssize_t</span> <span class="nf">unkillable_read</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">count</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="n">f_pos</span><span class="p">)</span> 
<span class="p">{</span> 
	<span class="k">struct</span> <span class="n">pid</span> <span class="o">*</span><span class="n">pid_struct</span><span class="p">;</span>
	<span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span>
	
	<span class="cm">/* interpret count to read as target pid */</span>
	<span class="n">printk</span><span class="p">(</span><span class="s">"Unkillable: Got pid %d"</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">count</span><span class="p">);</span>

	<span class="cm">/* get the pid struct */</span>
	<span class="n">pid_struct</span> <span class="o">=</span> <span class="n">find_get_pid</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span> <span class="n">count</span><span class="p">);</span>

	<span class="cm">/* get the task_struct from the pid */</span>
	<span class="n">p</span> <span class="o">=</span> <span class="n">pid_task</span><span class="p">(</span><span class="n">pid_struct</span><span class="p">,</span> <span class="n">PIDTYPE_PID</span><span class="p">);</span>

	<span class="cm">/* add the flag */</span>
	<span class="n">p</span><span class="o">-&gt;</span><span class="n">signal</span><span class="o">-&gt;</span><span class="n">flags</span> <span class="o">=</span> <span class="n">p</span><span class="o">-&gt;</span><span class="n">signal</span><span class="o">-&gt;</span><span class="n">flags</span> <span class="o">|</span> <span class="n">SIGNAL_UNKILLABLE</span><span class="p">;</span>
	<span class="n">printk</span><span class="p">(</span><span class="s">"Unkillable: pid %d marked as unkillable</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">count</span><span class="p">);</span>
	
	<span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">f_pos</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> 
		<span class="o">*</span><span class="n">f_pos</span><span class="o">+=</span><span class="mi">1</span><span class="p">;</span> 
		<span class="k">return</span> <span class="mi">1</span><span class="p">;</span> 
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span> 
		<span class="k">return</span> <span class="mi">0</span><span class="p">;</span> 
	<span class="p">}</span>
<span class="p">}</span>

<span class="kt">ssize_t</span> <span class="nf">unkillable_write</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">count</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="n">f_pos</span><span class="p">)</span> 
<span class="p">{</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The key part is the <code class="language-plaintext highlighter-rouge">unkillable_read()</code> function. This function is called when
we try to read from the device. The amount of bytes we are trying to read
is sent as the <code class="language-plaintext highlighter-rouge">count</code> parameter, which we abuse by reinterpreting as a pid.
With the pid in hand, we find the <code class="language-plaintext highlighter-rouge">task_struct</code> and <code class="language-plaintext highlighter-rouge">signal_struct</code> and mark
the process unkillable. The following makefile will build and install the
module.</p>
<h4 id="makefile"><em>Makefile</em></h4>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">obj-m</span> <span class="o">+=</span> unkillable.o

<span class="nl">all</span><span class="o">:</span>
	make <span class="nt">-C</span> /lib/modules/<span class="nf">$(</span><span class="nb">shell</span> <span class="nb">uname</span> <span class="nt">-r</span><span class="nf">)</span>/build <span class="nv">M</span><span class="o">=</span><span class="nv">$(PWD)</span> modules

<span class="nl">clean</span><span class="o">:</span>
	make <span class="nt">-C</span> /lib/modules/<span class="nf">$(</span><span class="nb">shell</span> <span class="nb">uname</span> <span class="nt">-r</span><span class="nf">)</span>/build <span class="nv">M</span><span class="o">=</span><span class="nv">$(PWD)</span> clean

<span class="nl">install</span><span class="o">:</span>
	<span class="nb">sudo </span>insmod unkillable.ko

<span class="nl">uninstall</span><span class="o">:</span>
	<span class="nb">sudo </span>rmmod unkillable

<span class="nl">mknod</span><span class="o">:</span>
	<span class="nb">sudo mknod</span> /dev/unkillable c 117 0
	<span class="nb">sudo chmod </span>666 /dev/unkillable
</code></pre></div></div>
<p>Now we just need a simple program to test our module with.</p>
<h4 id="immortal_processc"><em>immortal_process.c</em></h4>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;fcntl.h&gt;
#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
	<span class="kt">int</span> <span class="n">fd</span><span class="p">;</span>
	<span class="kt">char</span> <span class="n">c</span><span class="p">;</span>
	<span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span>
	<span class="kt">int</span> <span class="n">my_pid</span> <span class="o">=</span> <span class="n">getpid</span><span class="p">();</span>

	<span class="n">printf</span><span class="p">(</span><span class="s">"My pid: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">my_pid</span><span class="p">);</span>
	<span class="n">fd</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="s">"/dev/unkillable"</span><span class="p">,</span> <span class="n">O_RDWR</span><span class="p">);</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">fd</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"Error opening /dev/unkillable</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"Opened /dev/unkillable</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
	<span class="n">read</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">c</span><span class="p">,</span> <span class="n">my_pid</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"We are now unkillable!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
	<span class="n">read</span><span class="p">(</span><span class="n">STDIN_FILENO</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"exiting on user input...</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now let’s put it all together. You can copy the above files into the same
folder.</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">ls
</span>immortal_process.c  Makefile  unkillable.c
<span class="nv">$ </span>cc immortal_process.c 
<span class="nv">$ </span>make
make <span class="nt">-C</span> /lib/modules/5.4.0-7634-generic/build <span class="nv">M</span><span class="o">=</span>/home/user/unkillable modules
make[1]: Entering directory <span class="s1">'/usr/src/linux-headers-5.4.0-7634-generic'</span>
  CC <span class="o">[</span>M]  /home/user/unkillable/unkillable.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC <span class="o">[</span>M]  /home/user/unkillable/unkillable.mod.o
  LD <span class="o">[</span>M]  /home/user/unkillable/unkillable.ko
make[1]: Leaving directory <span class="s1">'/usr/src/linux-headers-5.4.0-7634-generic'</span>
<span class="nv">$ </span>make <span class="nb">mknod
sudo mknod</span> /dev/unkillable c 117 0
<span class="nb">sudo chmod </span>666 /dev/unkillable
<span class="nv">$ </span>make <span class="nb">install
sudo </span>insmod unkillable.ko
<span class="nv">$ </span>
</code></pre></div></div>
<p>And if we check dmesg:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>14538.243110] Inserting unkillable module
</code></pre></div></div>
<p>Now we can run our application:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./a.out 
My pid: 45953
Opened /dev/unkillable
We are now unkillable!
</code></pre></div></div>
<p>From a second terminal we can check dmesg again:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>14750.576795] Unkillable: Got pid 45953
<span class="o">[</span>14750.576796] Unkillable: pid 45953 marked as unkillable
</code></pre></div></div>
<p>And try to kill the process:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">kill</span> <span class="nt">-9</span> 45953
<span class="nv">$ </span><span class="nb">kill</span> <span class="nt">-2</span> 45953
<span class="nv">$ </span><span class="nb">kill</span> <span class="nt">-15</span> 45953
<span class="nv">$ </span><span class="nb">sudo kill</span> <span class="nt">-9</span> 45953
<span class="o">[</span><span class="nb">sudo</span><span class="o">]</span> password <span class="k">for </span>user: 
<span class="nv">$ </span><span class="nb">sudo kill</span> <span class="nt">-9</span> 45953
<span class="nv">$ </span>ps aux | <span class="nb">grep</span> <span class="s1">'a\.out'</span>
user    45953  0.0  0.0   2492   584 pts/4    S+   21:16   0:00 ./a.out
</code></pre></div></div>
<p>Try as we might, we cannot kill the process. Not even as root! The only way
to end the process is by giving it some input it can read so it will end
on its own. Reading input here is just an example, the process could be
performing any task. The point is that the process will continue, unkillable,
until it decides to end or the system shuts down.</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./a.out 
My pid: 45953
Opened /dev/unkillable
We are now unkillable!

exiting on user input...
<span class="nv">$ </span>
</code></pre></div></div>
<h1 id="can-sigkill-be-caught">Can SIGKILL be caught?</h1>
<p>So what comes next? It’s worth pointing out that while our process is immortal,
it still cannot catch a <code class="language-plaintext highlighter-rouge">SIGKILL</code> signal. It just ignores them. Why is this?
If we search the kernel source for references to <code class="language-plaintext highlighter-rouge">SIGNAL_UNKILLABLE</code> we find
the <a href="https://elixir.bootlin.com/linux/latest/source/kernel/signal.c#L79">following snippet</a>
in <code class="language-plaintext highlighter-rouge">kernel/signal.c</code>.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">bool</span> <span class="nf">sig_task_ignored</span><span class="p">(</span><span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">t</span><span class="p">,</span> <span class="kt">int</span> <span class="n">sig</span><span class="p">,</span> <span class="n">bool</span> <span class="n">force</span><span class="p">)</span>
<span class="p">{</span>
	<span class="kt">void</span> <span class="n">__user</span> <span class="o">*</span><span class="n">handler</span><span class="p">;</span>

	<span class="n">handler</span> <span class="o">=</span> <span class="n">sig_handler</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">sig</span><span class="p">);</span>

	<span class="cm">/* SIGKILL and SIGSTOP may not be sent to the global init */</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">unlikely</span><span class="p">(</span><span class="n">is_global_init</span><span class="p">(</span><span class="n">t</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">sig_kernel_only</span><span class="p">(</span><span class="n">sig</span><span class="p">)))</span>
		<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>

	<span class="k">if</span> <span class="p">(</span><span class="n">unlikely</span><span class="p">(</span><span class="n">t</span><span class="o">-&gt;</span><span class="n">signal</span><span class="o">-&gt;</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">SIGNAL_UNKILLABLE</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
	    <span class="n">handler</span> <span class="o">==</span> <span class="n">SIG_DFL</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="p">(</span><span class="n">force</span> <span class="o">&amp;&amp;</span> <span class="n">sig_kernel_only</span><span class="p">(</span><span class="n">sig</span><span class="p">)))</span>
		<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>

	<span class="cm">/* Only allow kernel generated signals to this kthread */</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">unlikely</span><span class="p">((</span><span class="n">t</span><span class="o">-&gt;</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">PF_KTHREAD</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
		     <span class="p">(</span><span class="n">handler</span> <span class="o">==</span> <span class="n">SIG_KTHREAD_KERNEL</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">force</span><span class="p">))</span>
		<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>

	<span class="k">return</span> <span class="n">sig_handler_ignored</span><span class="p">(</span><span class="n">handler</span><span class="p">,</span> <span class="n">sig</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If we look for <a href="https://elixir.bootlin.com/linux/latest/source/kernel/signal.c#L101">where <code class="language-plaintext highlighter-rouge">sig_task_ignored()</code> is called</a>
we find:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">bool</span> <span class="nf">sig_ignored</span><span class="p">(</span><span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">t</span><span class="p">,</span> <span class="kt">int</span> <span class="n">sig</span><span class="p">,</span> <span class="n">bool</span> <span class="n">force</span><span class="p">)</span>
<span class="p">{</span>
	<span class="cm">/*
	 * Blocked signals are never ignored, since the
	 * signal handler may change by the time it is
	 * unblocked.
	 */</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">sigismember</span><span class="p">(</span><span class="o">&amp;</span><span class="n">t</span><span class="o">-&gt;</span><span class="n">blocked</span><span class="p">,</span> <span class="n">sig</span><span class="p">)</span> <span class="o">||</span> <span class="n">sigismember</span><span class="p">(</span><span class="o">&amp;</span><span class="n">t</span><span class="o">-&gt;</span><span class="n">real_blocked</span><span class="p">,</span> <span class="n">sig</span><span class="p">))</span>
		<span class="k">return</span> <span class="nb">false</span><span class="p">;</span>

	<span class="cm">/*
	 * Tracers may want to know about even ignored signal unless it
	 * is SIGKILL which can't be reported anyway but can be ignored
	 * by SIGNAL_UNKILLABLE task.
	 */</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">t</span><span class="o">-&gt;</span><span class="n">ptrace</span> <span class="o">&amp;&amp;</span> <span class="n">sig</span> <span class="o">!=</span> <span class="n">SIGKILL</span><span class="p">)</span>
		<span class="k">return</span> <span class="nb">false</span><span class="p">;</span>

	<span class="k">return</span> <span class="n">sig_task_ignored</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">force</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And if we go one layer further up, we find <a href="https://elixir.bootlin.com/linux/latest/source/kernel/signal.c#L961">where <code class="language-plaintext highlighter-rouge">sig_ignored()</code> is called</a>
we find the <a href="https://elixir.bootlin.com/linux/latest/source/kernel/signal.c#L899"><code class="language-plaintext highlighter-rouge">prepare_signal()</code> function</a>
which has the following helpful comment:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * Handle magic process-wide effects of stop/continue signals. Unlike
 * the signal actions, these happen immediately at signal-generation
 * time regardless of blocking, ignoring, or handling.  This does the
 * actual continuing for SIGCONT, but not the actual stopping for stop
 * signals. The process stop is done as a signal action for SIG_DFL.
 *
 * Returns true if the signal should be actually delivered, otherwise
 * it should be dropped.
 */</span>
</code></pre></div></div>
<p>Indeed, we see the final line of this function is:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	<span class="k">return</span> <span class="o">!</span><span class="n">sig_ignored</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">force</span><span class="p">);</span>
</code></pre></div></div>
<p>Thus, if our process has <code class="language-plaintext highlighter-rouge">SIGNAL_UNKILLABLE</code> set, then <code class="language-plaintext highlighter-rouge">sig_task_ignored()</code>
returns true, which causes <code class="language-plaintext highlighter-rouge">sig_ignored()</code> to return true, which causes
<code class="language-plaintext highlighter-rouge">prepare_signal()</code> to return false, which indicates that the signal should
be ignored. At no point do we get to our process’s signal handling functions,
the signal is simply dropped.</p>
<p>Additionally, in the main loop of <a href="https://elixir.bootlin.com/linux/latest/source/kernel/signal.c#L2526"><code class="language-plaintext highlighter-rouge">get_signal()</code></a>
we find <a href="https://elixir.bootlin.com/linux/latest/source/kernel/signal.c#L2673">the following code segment</a>:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>		<span class="cm">/*
		 * Global init gets no signals it doesn't want.
		 * Container-init gets no signals it doesn't want from same
		 * container.
		 *
		 * Note that if global/container-init sees a sig_kernel_only()
		 * signal here, the signal must have been generated internally
		 * or must have come from an ancestor namespace. In either
		 * case, the signal cannot be dropped.
		 */</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">unlikely</span><span class="p">(</span><span class="n">signal</span><span class="o">-&gt;</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">SIGNAL_UNKILLABLE</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
				<span class="o">!</span><span class="n">sig_kernel_only</span><span class="p">(</span><span class="n">signr</span><span class="p">))</span>
			<span class="k">continue</span><span class="p">;</span>
</code></pre></div></div>
<p>Now, the comment says “global init,” but the code only checks for
<code class="language-plaintext highlighter-rouge">SIGNAL_UNKILLABLE</code>. If it finds that flag, it continues to the next loop
iteration and ignores the signal. So that’s two places where <code class="language-plaintext highlighter-rouge">SIGKILL</code> might
be ignored on a process flagged <code class="language-plaintext highlighter-rouge">SIGNAL_UNKILLABLE</code>.</p>
<p>I experimented with registering a <a href="https://embetronicx.com/tutorials/linux/device-drivers/linux-device-drivers-tutorial-kernel-thread/">kthread</a>
and using that <code class="language-plaintext highlighter-rouge">task_struct</code> as the <code class="language-plaintext highlighter-rouge">signal-&gt;group_exit_task</code>. The idea is
that when receiving a <code class="language-plaintext highlighter-rouge">SIGKILL</code> the kernel thread would use a
<a href="https://developer.ibm.com/technologies/linux/articles/l-user-space-apps/">helper function</a>
that could call <code class="language-plaintext highlighter-rouge">kill</code> to send a <code class="language-plaintext highlighter-rouge">SIGUSR1</code> to the immortal process. The
immortal process can then interpret this <code class="language-plaintext highlighter-rouge">SIGUSR1</code> as “someone is trying
to kill you,” and act appropriately. I have not, however, been able to get
this working. Attempting to replace the <code class="language-plaintext highlighter-rouge">group_exit_task</code> just causes the
process to hang when receiving signals. I’m probably doing something wrong,
I just have to figure it out.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[  364.138308] INFO: task unkillable signal thread:4948 blocked for more than 120 seconds.
[  364.138316]       Tainted: P           OE     5.4.0-7634-generic #38~1592497129~20.04~9a1ea2e-Ubuntu
[  364.138319] "echo 0 &gt; /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[  364.138322] test thread     D    0  4948      2 0x80004000
[  364.138328] Call Trace:
[  364.138340]  __schedule+0x2e3/0x740
[  364.138345]  schedule+0x42/0xb0
[  364.138351]  kthread+0xd5/0x140
[  364.138361]  ? init_module+0x6b/0x6b [memory]
[  364.138365]  ? kthread_park+0x90/0x90
[  364.138371]  ret_from_fork+0x35/0x40
</code></pre></div></div>
<p>And by posting this publicly on the Internet, I’m hoping some kind stranger
sets out to <a href="https://meta.wikimedia.org/wiki/Cunningham%27s_Law">prove me wrong</a>
and show me how it can be done.</p>
</div><a class="u-url" href="/linux/2020/07/05/UNKILLABLE.html" hidden></a>
</article>
</div>
</main><footer class="site-footer h-card">
<data class="u-url" href="/"></data>
<div class="wrapper">
<h2 class="footer-heading"><a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6f091d060b0e162f001d1b0615411c07">[email&#160;protected]</a>:~$</h2>
<div class="footer-col-wrapper">
<div class="footer-col footer-col-1">
<ul class="contact-list">
<li class="p-name">Friday Ortiz</li><li><a class="u-email" href="/cdn-cgi/l/email-protection#d1a3b0b7b0b4bd91bea3a5b8abffa2b9"><span class="__cf_email__" data-cfemail="dba9babdbabeb79bb4a9afb2a1f5a8b3">[email&#160;protected]</span></a></li></ul>
</div>
<div class="footer-col footer-col-2"><ul class="social-media-list"><li><a href="https://github.com/FridayOrtiz"><svg class="svg-icon"><use xlink:href="/assets/minima-social-icons.svg#github"></use></svg> <span class="username">FridayOrtiz</span></a></li><li><a href="https://www.linkedin.com/in/rafael-ortiz"><svg class="svg-icon"><use xlink:href="/assets/minima-social-icons.svg#linkedin"></use></svg> <span class="username">rafael-ortiz</span></a></li> <li><a rel="me" href="https://tragi.cc/@Senicar"><svg class="svg-icon"><use xlink:href="/assets/minima-social-icons.svg#mastodon"></use></svg> <span class="username">Senicar</span></a></li> <li><a rel="me" href="https://infosec.exchange/@Senicar"><svg class="svg-icon"><use xlink:href="/assets/minima-social-icons.svg#mastodon"></use></svg> <span class="username">Senicar</span></a></li><li><a href="https://www.twitter.com/FridayOrtiz"><svg class="svg-icon"><use xlink:href="/assets/minima-social-icons.svg#twitter"></use></svg> <span class="username">FridayOrtiz</span></a></li></ul>
</div>
<div class="footer-col footer-col-3">
<p>The new original cyber dog. Linux, crypto(graphy), Machine Learning.</p>

</div>
</div>
</div>
</footer>
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script defer src="https://static.cloudflareinsights.com/beacon.min.js/vaafb692b2aea4879b33c060e79fe94621666317369993" integrity="sha512-0ahDYl866UMhKuYcW078ScMalXqtFJggm7TmlUtp0UlD4eQk0Ixfnm5ykXKvGJNFjLMoortdseTfsRT8oCfgGA==" data-cf-beacon='{"rayId":"76d13cd44a6a72b4","version":"2022.11.0","r":1,"token":"a79d1cd0bbb14e87a791ad1788cac271","si":100}' crossorigin="anonymous"></script>
</body>
</html>
</body>
</html>
